package com.os.ops;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.os.config.ConfigInit;
import com.os.constant.Sys;
import com.os.data.DataHashCache;
import com.os.exception.Asserts;
import com.os.util.ByteConvertUtil;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 风亦未止
 * @date 2023/5/2 17:33
 */
@Log4j2
@Component
public class TempObj {
    @Autowired
    private ConfigInit configInit;

    // uuid, FileOutputStream
    private ConcurrentHashMap<String, FileOutputStream> outputMap = new ConcurrentHashMap<>();

    /**
     * 生成临时对象，返回uuid
     * @param hash
     * @param size
     * @return
     */
    @SneakyThrows
    public String postTemp(String hash, int size)  {
        String uuid = UUID.randomUUID().toString();
        TempInfo tempInfo = new TempInfo(uuid, hash, size);
        tempInfo.writeToFile(configInit.tempRootPath);
        openOutputStream(uuid);
        return uuid;
    }

    /**
     * 临时文件写入数据
     * @param in
     * @param uuid
     * @return
     * @throws IOException
     */
    @SneakyThrows
    public boolean patch(InputStream in, String uuid){
        TempInfo tempInfo = readTempInfo(uuid);
        if(tempInfo == null){
            return false;
        }
        FileOutputStream outputStream = outputMap.get(uuid);
        IoUtil.copy(in, outputStream);
        return true;
    }

    /**
     * 转正临时文件
     */
    @SneakyThrows
    public void put(String uuid){
        TempInfo tempInfo = readTempInfo(uuid);
        if(tempInfo == null){
            return;
        }
        FileOutputStream outputStream = outputMap.get(uuid);
        outputStream.close();
        outputMap.remove(uuid);

        String dataPath = configInit.dataPath + Sys.SEPARATOR + tempInfo.hash;
        String tempInfoPath = configInit.tempRootPath + Sys.SEPARATOR + uuid;
        String dataTempPath =  tempInfoPath + ".dat";

        File temp = new File(dataTempPath);
        File target = new File(dataPath);
        temp.renameTo(target);
        //删除临时文件信息
        File tempInf = new File(tempInfoPath);
        tempInf.delete();
    }

    /**
     * 删除临时文件
     */
    @SneakyThrows
    public void delete(String uuid){
        FileOutputStream outputStream = outputMap.get(uuid);
        outputStream.close();
        outputMap.remove(uuid);
        String tempInfoPath = configInit.tempRootPath + Sys.SEPARATOR + uuid;
        String dataTempPath =  tempInfoPath + ".dat";
        File tempInfoFile = new File(tempInfoPath);
        File dataTempFile = new File(dataTempPath);
        tempInfoFile.delete();
        dataTempFile.delete();
    }


    /**
     * 读取 磁盘中的 TempInfo
     * @param uuid
     * @return
     * @throws IOException
     */
    private TempInfo readTempInfo(String uuid) throws IOException {
        String path = configInit.tempRootPath + Sys.SEPARATOR + uuid;
        TempInfo tempInfo;
        try (FileInputStream inputStream = new FileInputStream(path)){
            byte[] read = new byte[inputStream.available()];
            inputStream.read(read);
            tempInfo = (TempInfo) ByteConvertUtil.toObj(read, TempInfo.class);
        }
        return tempInfo;
    }


    private void openOutputStream(String uuid) throws FileNotFoundException {
        String tempDataPath = configInit.tempRootPath + Sys.SEPARATOR + uuid + ".dat";
        FileOutputStream out = new FileOutputStream(tempDataPath);
        outputMap.put(uuid,out);
    }


    @Data
    public static class TempInfo implements Serializable{
        private String uuid;
        private String hash;
        private int size;

        public TempInfo(String uuid, String hash, int size) {
            this.uuid = uuid;
            this.hash = hash;
            this.size = size;
        }

        public void writeToFile(String tempRootPath) throws IOException {
            File file = new File(tempRootPath + Sys.SEPARATOR + uuid);
            log.info(tempRootPath + Sys.SEPARATOR + uuid);
            try( FileOutputStream outputStream = new FileOutputStream(file)) {
                outputStream.write(ByteConvertUtil.toByte(this));
            }
        }

    }

}
